#include "../global.h"

#include "vtkClipPolyData.h"
#include "vtkContourFilter.h"
#include "vtkImageFlip.h"
#include "vtkSmoothPolyDataFilter.h"
#include "vtkTriangle.h"
#include "vtkConeSource.h"

class vtkTIPWCallback : public vtkCommand
{
public:
    static vtkTIPWCallback *New()
    {
        return new vtkTIPWCallback;
    }

    virtual void Execute(vtkObject *caller, unsigned long , void *)
    {
        vtkImplicitPlaneWidget2 *pWidget = reinterpret_cast<vtkImplicitPlaneWidget2*>(caller);
        if(pWidget)
        {
            vtkImplicitPlaneRepresentation *rep =
            reinterpret_cast<vtkImplicitPlaneRepresentation*>(pWidget->GetRepresentation());
            rep->GetPlane(m_plane);

            m_cliper->SetClipFunction(m_plane);
            m_cliper->Update();

            vtkCreate(clipedData, vtkPolyData);
            clipedData->DeepCopy(m_cliper->GetOutput());

            vtkCreate(coneMapper, vtkPolyDataMapper);
            coneMapper->SetInputData(clipedData);
            coneMapper->ScalarVisibilityOff();
            m_actor->SetMapper(coneMapper);
        }
    }
    void setParameter(vtkPlane *p, vtkActor *a, vtkClipPolyData *c)
    {
        m_plane = p;
        m_actor = a;
        m_cliper = c;
    }
protected:
    vtkTIPWCallback():m_plane(0),m_actor(0),m_cliper(0){}
    vtkPlane* m_plane;
    vtkActor* m_actor;
    vtkClipPolyData* m_cliper;

};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    VTK_MODULE_INIT(vtkRenderingOpenGL);
    vtkCreate(renderer, vtkRenderer);
    vtkCreate(renWin, vtkRenderWindow);
    vtkCreate(iren, vtkRenderWindowInteractor);
    vtkCreate(renderer2, vtkRenderer);

    renWin->AddRenderer(renderer);
    renWin->AddRenderer(renderer2);
    iren->SetRenderWindow(renWin);

    renderer2->SetBackground( 0.2, 0.3, 0.5 );
    renderer2->SetViewport(0.5, 0.0, 1.0, 1.0);

    vtkCreate(reader, vtkDICOMImageReader);
    reader->SetDataByteOrderToLittleEndian();
    reader->SetDirectoryName(path.toStdString().c_str());
    reader->Update();

    vtkCreate(skinExtractor, vtkContourFilter);
    vtkCreate(flip, vtkImageFlip);
    flip->SetInputConnection( reader->GetOutputPort());
    flip->SetFilteredAxes(1);
    skinExtractor->SetInputConnection(flip->GetOutputPort());
    skinExtractor->SetValue(0, 100);

    vtkCreate(smooth, vtkSmoothPolyDataFilter);
    smooth->SetInputConnection(skinExtractor->GetOutputPort());
    smooth->SetNumberOfIterations( 500 );
    vtkCreate(skinNormals, vtkPolyDataNormals);
    skinNormals->SetInputConnection(smooth->GetOutputPort());
    skinNormals->SetFeatureAngle(60.0);
    vtkCreate(skinStripper, vtkStripper);
    skinStripper->SetInputConnection(skinNormals->GetOutputPort());
    vtkCreate(skinMapper, vtkPolyDataMapper);
    skinMapper->SetInputConnection(skinStripper->GetOutputPort());
    skinMapper->ScalarVisibilityOff();

    vtkCreate(skin, vtkActor);
    skin->SetMapper(skinMapper);
    vtkCreate(backProp, vtkProperty);
    backProp->SetDiffuseColor(1.0, 0.8, 0.85);
    skin->SetBackfaceProperty(backProp);

    vtkCreate(outlineData, vtkOutlineFilter);
    outlineData->SetInputConnection(flip->GetOutputPort());

    vtkCreate(mapOutline, vtkPolyDataMapper);
    mapOutline->SetInputConnection(outlineData->GetOutputPort());

    vtkCreate(outline, vtkActor);
    outline->SetMapper(mapOutline);
    outline->GetProperty()->SetColor(0, 0, 0);

    vtkCreate(aCamera, vtkCamera);
    aCamera->SetViewUp (0, 0, 1);
    aCamera->SetPosition (0, 1, 0);
    aCamera->SetFocalPoint (0, 0, 0);
    aCamera->ComputeViewPlaneNormal();
    aCamera->Azimuth(30.0);
    aCamera->Elevation(30.0);

    renderer->AddActor(outline);
    renderer->AddActor(skin);
    renderer->SetActiveCamera(aCamera);
    renderer->ResetCamera();
    aCamera->Dolly(1.5);

    renderer->SetBackground(.2, .3, .4);
    renWin->SetSize(640, 480);
    renderer->ResetCameraClippingRange ();

    vtkCreate(style, vtkInteractorStyleTrackballCamera);
    iren->SetInteractorStyle( style );

    double point1[3] = {60, 61, 0};
    double point2[3] = {51, 65, 55};
    double point3[3] = {78, 45, 114};
    double normal[3];

    vtkCreate(planeNew, vtkPlane);
    vtkTriangle::ComputeNormal(point1, point2, point3, normal);
    planeNew->SetOrigin(point1);
    planeNew->SetNormal(normal);

//#ifndef Render_2
    vtkCreate(cone, vtkConeSource);
    cone->SetHeight( 3.0 );
    cone->SetRadius( 1.0 );
    cone->SetResolution( 10 );

    vtkCreate(coneMapper, vtkPolyDataMapper);
    coneMapper->SetInputConnection(skinStripper->GetOutputPort());
    coneMapper->ScalarVisibilityOff();
    vtkCreate(coneSkinActor, vtkActor);
    coneSkinActor->SetMapper( coneMapper );
    coneSkinActor->SetBackfaceProperty(backProp);
    vtkCreate(coneOutline, vtkActor);
    coneOutline->SetMapper(mapOutline);
    coneOutline->GetProperty()->SetColor(0,0,0);

    renderer2->AddActor(outline);
    renderer2->AddActor(coneSkinActor);

    vtkCreate(rCamera, vtkCamera);
    rCamera->SetViewUp (0, 0, 1);
    rCamera->SetPosition (0, -1, 0);
    rCamera->SetFocalPoint (0, 0, 0);
    rCamera->ComputeViewPlaneNormal();
    rCamera->Azimuth(30.0);
    rCamera->Elevation(30.0);
    renderer2->SetActiveCamera(rCamera);
    renderer2->ResetCamera();

    vtkCreate(cliper, vtkClipPolyData);
    cliper->SetInputConnection(skinStripper->GetOutputPort());
    cliper->SetClipFunction(planeNew);
    cliper->Update();

    // set up representation for vtkImplicitPlaneWidget2
    // you could set the normal and origin with the value you want
    vtkCreate(rep, vtkImplicitPlaneRepresentation);
    rep->SetPlaceFactor(1.25); // This must be set prior to placing the widget
    rep->PlaceWidget(coneSkinActor->GetBounds());

    vtkCreate(implicitPlaneWidget, vtkImplicitPlaneWidget2);
    implicitPlaneWidget->SetInteractor(iren);
    // this set the representation for the widget thus the normal and origin is transfer to the widget
    implicitPlaneWidget->SetRepresentation(rep);

    vtkCreate(pCall, vtkTIPWCallback);
    pCall->setParameter(planeNew,coneSkinActor,cliper);

    implicitPlaneWidget->AddObserver(vtkCommand::EndInteractionEvent, pCall);
    implicitPlaneWidget->On();

    renWin->Render();
    iren->Initialize();
    iren->Start();

    return a.exec();
}
